/*
 * Ganesa Copyright (C) 2008 Wim Crols <twimpiex@gnx.be>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package be.gnx.ganesa.application.main;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Vector;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

public final class PluginsLoader {

  public PluginsLoader(Vector<File> pluginsDirectories) {
    for (File pluginsDirectory : pluginsDirectories) {
      if (pluginsDirectory.exists() && pluginsDirectory.isDirectory()) {
        for (File pluginFile : pluginsDirectory.listFiles(new FileFilter() {
          public boolean accept(File pathname) {
            if (pathname.getAbsolutePath().endsWith(".jar"))
              return true;
            return false;
          }
        })) {
          try {
            addFileToClassLoader(pluginFile);
            load(pluginFile, pluginsDirectory);
          } catch (IOException ioException) {
            System.out.println("Error while loading plugin. Traceback: ");
            ioException.printStackTrace();
            System.exit(1);
          } catch (ClassNotFoundException classNotFoundException) {
            System.out.println("Error while loading plugin. Traceback: ");
            classNotFoundException.printStackTrace();
            System.exit(1);
          } catch (InstantiationException instantiationException) {
            System.out.println("Error while loading plugin. Traceback: ");
            instantiationException.printStackTrace();
            System.exit(1);
          } catch (IllegalAccessException illegalAccessException) {
            System.out.println("Error while loading plugin. Traceback: ");
            illegalAccessException.printStackTrace();
            System.exit(1);
          }
        }
      }
    }
  }

  private void load(File jarFile, File classPathFile) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
    JarFile pluginJarFile = new JarFile(jarFile);
    Attributes mainAttributes = pluginJarFile.getManifest().getMainAttributes();
    if (mainAttributes != null) {
      String mainAttribute = mainAttributes.getValue("Main-Class");
      Class clazz = getClass().getClassLoader().loadClass(mainAttribute);
      clazz.newInstance();
    }
  }

  private void addFileToClassLoader(String string) throws IOException {
    File file = new File(string);
    addFileToClassLoader(file);
  }

  private void addFileToClassLoader(File file) throws IOException {
    addUrlToClassLoader(file.toURI().toURL());
  }

  private void addUrlToClassLoader(URL url) throws IOException {
    URLClassLoader systemClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

    try {
      Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
      method.setAccessible(true);
      method.invoke(systemClassLoader, new Object[] { url });
    } catch (Throwable throwable) {
      IOException ioException = new IOException("Error, could not add URL to system classloader", throwable);
      while (throwable != null) {
        throwable.printStackTrace();
        throwable = throwable.getCause();
      }
      throw ioException;
    }
  }

}
